using NHibernate;
using Project.Library.Core;
using Project.Library.Core.DBC;

namespace Project.Library.NHibernate
{
    /// <summary>
    /// Implementation of a Unit of Work
    /// </summary>
    public class NHUnitOfWorkImpl : Disposable, INHUnitOfWork
    {
        private readonly IActiveSessionManager activeSessionManager;
        private readonly ITransactionManager transactionManager;
        private readonly ISession currentSession;

        /// <summary>
        /// Initializes a new instance of the <see cref="NHUnitOfWorkImpl"/> class.
        /// </summary>
        /// <param name="activeSessionManager">The active session manager.</param>
        /// <param name="transactionManager">The transaction manager.</param>
        public NHUnitOfWorkImpl(IActiveSessionManager activeSessionManager, ITransactionManager transactionManager)
        {
            this.activeSessionManager = activeSessionManager;
            this.transactionManager = transactionManager;
            currentSession = activeSessionManager.GetActiveSession();
            currentSession.FlushMode = FlushMode.Commit;
        }

        /// <summary>
        /// Gets the transaction.
        /// </summary>
        /// <value>The transaction.</value>
        public ITransactionManager Transaction
        {
            get { return transactionManager; }
        }

        /// <summary>
        /// Gets the current session. Allows the user to access the session
        /// for more specific work
        /// </summary>
        /// <returns></returns>
        public ISession GetCurrentSession()
        {
            Checks.Require(currentSession != null,
                           "There is no session started. You must call NHUnitOfWork.Start() before using the session");
            return currentSession;
        }

        /// <summary>
        /// Flushes all the pendent operations in session.
        /// </summary>
        public void Flush()
        {
            currentSession.Flush();
        }

        /// <summary>
        /// Creates an instance of QueryBatcher.
        /// </summary>
        /// <returns></returns>
        public IQueryBatcher CreateQueryBatcher()
        {
            return new QueryBatcher(currentSession);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if(! disposing) return;

            activeSessionManager.ClearActiveSession();

            if(currentSession != null)
            {
                currentSession.Close();
                currentSession.Dispose();
            }
        }
    }
}